#include "proc.h"
#include "memory.h"

extern void _map(_Protect *as, void *vs, void *pa);

static void *pf = NULL;

void* new_page(void) {
  assert(pf < (void *)_heap.end);
  void *p = pf;
  pf += PGSIZE;
  return p;
}

void free_page(void *p) {
  panic("not implement yet");
}

/**
 * 调整进程的堆空间（brk指针）
 * @param new_brk 新的堆顶地址
 * @return 总是返回0（简化实现，未处理错误）
 */
int mm_brk(uint32_t new_brk) {
    // 如果当前堆顶未初始化（首次调用）
    if (current->cur_brk == 0) {
        // 初始化当前堆顶和最大堆顶为 new_brk
        current->cur_brk = current->max_brk = new_brk;
    } else {
        // 如果新堆顶需要扩展内存
        if (new_brk > current->max_brk) {
            // 计算需要扩展的内存长度
            int len = new_brk - current->max_brk;
            
            // 从当前最大堆顶的页对齐地址开始映射
            // PGROUNDUP 将地址向上对齐到页边界
            uintptr_t va = PGROUNDUP(current->max_brk);
            
            // 逐页分配物理内存并映射到虚拟地址空间
            while (len > 0) {
                // 分配一个新的物理页
                void *page = new_page();
                // 将虚拟地址 va 映射到物理页 page
                // _map 函数将关联进程地址空间 current->as 的页表
                _map(&current->as, (void *)va, page);
                // 移动到下一页
                va += PGSIZE;
                len -= PGSIZE;
            }
            // 更新最大堆顶为新的 new_brk
            current->max_brk = new_brk;
        }
        // 无论是否扩展内存，更新当前堆顶到 new_brk
        current->cur_brk = new_brk;
    }
    return 0;
}

void init_mm() {
  pf = (void *)PGROUNDUP((uintptr_t)_heap.start);
  Log("free physical pages starting from %p", pf);

  _pte_init(new_page, free_page);
}
